package com.wfh.mianshiji.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wfh.mianshiji.annotation.AuthCheck;
import com.wfh.mianshiji.common.BaseResponse;
import com.wfh.mianshiji.common.ErrorCode;
import com.wfh.mianshiji.common.ResultUtils;
import com.wfh.mianshiji.constant.UserConstant;
import com.wfh.mianshiji.exception.BusinessException;
import com.wfh.mianshiji.model.dto.interview.InterviewCreateRequest;
import com.wfh.mianshiji.model.dto.interview.InterviewQueryRequest;
import com.wfh.mianshiji.model.dto.interview.InterviewStartRequest;
import com.wfh.mianshiji.model.dto.interview.InterviewStopRequest;
import com.wfh.mianshiji.model.entity.Interview;
import com.wfh.mianshiji.model.vo.InterviewVo;
import com.wfh.mianshiji.service.InterviewService;
import com.wfh.mianshiji.tts.TtsStreamingService;
import com.wfh.mianshiji.tts.EnhancedTtsStreamingService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.Disposable;
import reactor.core.publisher.Flux;

import java.io.IOException;
import java.util.List;

/**
 * @Title: InterviewController
 * @Author wangfenghuan
 * @Package com.wfh.mianshiji.controller
 * @Date 2025/10/31 13:32
 * @description:
 */
@Slf4j
@RestController
@RequestMapping("/interview")
public class InterviewController {


    @Resource
    @Lazy
    private InterviewService interviewService;

    @Resource
    private TtsStreamingService ttsStreamingService;

    @Resource
    private EnhancedTtsStreamingService enhancedTtsStreamingService;


    /**
     * 开始面试
     *
     * @param interviewStartRequest
     * @param request
     * @return
     */
    @PostMapping("/start")
    public SseEmitter startInterview(@RequestBody InterviewStartRequest interviewStartRequest,
                                                        HttpServletRequest request) {
        SseEmitter emitter = new SseEmitter(300_000L);
        Long userId = interviewStartRequest.getUserId();
        Long interviewId = interviewStartRequest.getInterviewId();
        String message = interviewStartRequest.getMessage();

        if (userId == null || interviewId == null || StringUtils.isEmpty(message)) {
            emitter.completeWithError(new BusinessException(ErrorCode.PARAMS_ERROR));
            return emitter;
        }

        // 调用业务层获取 LLM 文本流
        Flux<String> textFlux = interviewService.start(userId, interviewId, message, request);

        Disposable subscription = textFlux.subscribe(
                chunk -> {
                    try {
                        emitter.send(chunk);
                    } catch (IOException e) {
                        emitter.completeWithError(e);
                    }
                },
                emitter::completeWithError,
                () -> {
                    try {
                        // 发送完成标记，通知前端流已结束
                        emitter.send("data: [DONE]\n\n");
                    } catch (IOException e) {
                        emitter.completeWithError(e);
                        return;
                    }
                    emitter.complete();
                }
        );

        emitter.onTimeout(subscription::dispose);
        emitter.onCompletion(subscription::dispose);

        return emitter;
        // 转为 TTS 音频流（SseMultiData）
        // Flux<SseMultiData> ttsFlux = ttsStreamingService.streamTextToAudio(textFlux);

// 转换为标准 SSE 格式（Base64 编码音频 + JSON）
        /*return ttsFlux.map(data -> {
                    // 注意：data.getAudio() 是 byte[]，不是 String！
                    String audioBase64 = Base64.getEncoder().encodeToString(data.getAudio()); // ✅ 关键修复

                    String payload = String.format(
                            "{\"text\":\"%s\",\"audio\":\"%s\"}",
                            escapeJson(data.getText()),
                            audioBase64
                    );
                    return ServerSentEvent.<String>builder()
                            .event("tts_chunk")
                            .data(payload)
                            .build();
                })
                .onErrorResume(throwable -> {
                    log.error("TTS 流异常", throwable);
                    String errorMsg = String.format("{\"error\":\"%s\"}", escapeJson(throwable.getMessage()));
                    return Flux.just(ServerSentEvent.<String>builder()
                            .event("error")
                            .data(errorMsg)
                            .build());
                });*/
    }

    /**
     * 创建面试
     *
     * @param interviewCreateRequest
     * @return
     */
    @PostMapping("/create")
    public BaseResponse<InterviewVo> create(@RequestBody InterviewCreateRequest interviewCreateRequest) {
        Long userId = interviewCreateRequest.getUserId();
        String jobTitle = interviewCreateRequest.getJobTitle();
        String jobDesc = interviewCreateRequest.getJobDesc();
        Long resumeId = interviewCreateRequest.getResumeId();
        if (!ObjectUtil.isAllNotEmpty(userId, jobDesc, jobTitle, resumeId)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        InterviewVo res = interviewService.create(interviewCreateRequest);
        return ResultUtils.success(res);
    }

    /**
     * 停止面试
     *
     * @param interviewStopRequest
     * @return
     */
    @PostMapping("/stop")
    public BaseResponse<Boolean> stop(@RequestBody InterviewStopRequest interviewStopRequest) {
        Long userId = interviewStopRequest.getUserId();
        Long interviewId = interviewStopRequest.getInterviewId();
        String message = interviewStopRequest.getMessage();
        if (!ObjectUtil.isAllNotEmpty(userId, interviewId, message)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Boolean res = interviewService.stop(interviewStopRequest);
        return ResultUtils.success(res);
    }

    /**
     * 管理员获取面试列表
     *
     * @param interviewQueryRequest
     * @return
     */
    @PostMapping("/page")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<List<InterviewVo>> page(@RequestBody InterviewQueryRequest interviewQueryRequest) {
        long current = interviewQueryRequest.getCurrent();
        long pageSize = interviewQueryRequest.getPageSize();
        if (!ObjectUtil.isAllNotEmpty(current, pageSize)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Page<Interview> interviewPage = interviewService.page(new Page<>(current, pageSize), new QueryWrapper<>(Interview.class));
        List<Interview> records = interviewPage.getRecords();
        List<InterviewVo> list = records.stream().map(interview -> BeanUtil.copyProperties(interview, InterviewVo.class)).toList();
        return ResultUtils.success(list);
    }

    /**
     * 用户获取面试列表
     *
     * @param interviewQueryRequest
     * @param userId
     * @return
     */
    @PostMapping("/get/{userId}")
    public BaseResponse<List<InterviewVo>> getByPage(@RequestBody InterviewQueryRequest interviewQueryRequest, @PathVariable("userId") Long userId) {
        long current = interviewQueryRequest.getCurrent();
        long pageSize = interviewQueryRequest.getPageSize();
        if (!ObjectUtil.isAllNotEmpty(current, pageSize)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Page<Interview> interviewPage = interviewService.page(new Page<>(current, pageSize), new QueryWrapper<>(Interview.class)
                .eq("userId", userId));
        List<Interview> records = interviewPage.getRecords();
        List<InterviewVo> list = records.stream().map(interview -> BeanUtil.copyProperties(interview, InterviewVo.class)).toList();
        return ResultUtils.success(list);
    }

    /**
     * ==========================================================================================================
     * 【新功能】带语音的面试接口 - 已注释
     * 这些接口提供了文本和语音同步返回的功能，支持PCM到MP3/WAV的转换
     * 需要时可以取消注释使用
     * ==========================================================================================================
     */

    /**
     * 开始面试 - 带语音返回（MP3格式）
     * 返回格式：{"type":"chunk","text":"文本内容","audio":"base64音频数据","format":"mp3"}
     *
    * @param interviewStartRequest
     * @param request
     * @return
     */
    /*@PostMapping(value = "/start-with-audio", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> startInterviewWithAudio(@RequestBody InterviewStartRequest interviewStartRequest,
                                               HttpServletRequest request) {
        Long userId = interviewStartRequest.getUserId();
        Long interviewId = interviewStartRequest.getInterviewId();
        String message = interviewStartRequest.getMessage();

        if (userId == null || interviewId == null || StringUtils.isEmpty(message)) {
            return Flux.just("{\"type\":\"error\",\"message\":\"参数错误\"}");
        }

        // 获取文本流
        Flux<String> textFlux = interviewService.start(userId, interviewId, message, request);

        // 转换为带音频的流
        return enhancedTtsStreamingService.createMultiFormatSseStream(textFlux, "mp3");
    }*/

    /**
     * 开始面试 - 带语音返回（WAV格式）
     * WAV格式包含完整的音频头信息，更容易播放
     *
     * @param interviewStartRequest
     * @param request
     * @return
     */
    /*@PostMapping(value = "/start-with-wav", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> startInterviewWithWav(@RequestBody InterviewStartRequest interviewStartRequest,
                                             HttpServletRequest request) {
        Long userId = interviewStartRequest.getUserId();
        Long interviewId = interviewStartRequest.getInterviewId();
        String message = interviewStartRequest.getMessage();

        if (userId == null || interviewId == null || StringUtils.isEmpty(message)) {
            return Flux.just("{\"type\":\"error\",\"message\":\"参数错误\"}");
        }

        Flux<String> textFlux = interviewService.start(userId, interviewId, message, request);

        return enhancedTtsStreamingService.createMultiFormatSseStream(textFlux, "wav");
    }*/

    /**
     * 开始面试 - 带语音返回（PCM格式，Base64编码）
     * 直接返回原始PCM数据的Base64编码
     *
     * @param interviewStartRequest
     * @param request
     * @return
     */
    /*@PostMapping(value = "/start-with-pcm", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> startInterviewWithPcm(@RequestBody InterviewStartRequest interviewStartRequest,
                                             HttpServletRequest request) {
        Long userId = interviewStartRequest.getUserId();
        Long interviewId = interviewStartRequest.getInterviewId();
        String message = interviewStartRequest.getMessage();

        if (userId == null || interviewId == null || StringUtils.isEmpty(message)) {
            return Flux.just("{\"type\":\"error\",\"message\":\"参数错误\"}");
        }

        Flux<String> textFlux = interviewService.start(userId, interviewId, message, request);

        return enhancedTtsStreamingService.createMultiFormatSseStream(textFlux, "pcm");
    }*/

    /**
     * 完整的SSE返回接口 - 同时返回文本和音频
     * 这个接口演示了如何返回更复杂的数据结构
     *
     * @param interviewStartRequest
     * @param request
     * @return
     */
    /*@PostMapping(value = "/start-full-audio", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter startInterviewFullAudio(@RequestBody InterviewStartRequest interviewStartRequest,
                                            HttpServletRequest request) {
        SseEmitter emitter = new SseEmitter(300_000L);
        Long userId = interviewStartRequest.getUserId();
        Long interviewId = interviewStartRequest.getInterviewId();
        String message = interviewStartRequest.getMessage();
        String audioFormat = "mp3"; // 可以从请求参数获取

        if (userId == null || interviewId == null || StringUtils.isEmpty(message)) {
            emitter.completeWithError(new BusinessException(ErrorCode.PARAMS_ERROR));
            return emitter;
        }

        // 获取文本流
        Flux<String> textFlux = interviewService.start(userId, interviewId, message, request);

        // 获取带音频的流
        Flux<String> audioTextFlux = enhancedTtsStreamingService.createMultiFormatSseStream(textFlux, audioFormat);

        Disposable subscription = audioTextFlux.subscribe(
                chunk -> {
                    try {
                        // 发送SSE格式的数据
                        emitter.send(SseEmitter.event()
                                .name("message")
                                .data(chunk));
                    } catch (IOException e) {
                        emitter.completeWithError(e);
                    }
                },
                emitter::completeWithError,
                () -> {
                    try {
                        emitter.send(SseEmitter.event()
                                .name("done")
                                .data("{\"type\":\"done\"}"));
                        emitter.complete();
                    } catch (IOException e) {
                        emitter.completeWithError(e);
                    }
                }
        );

        emitter.onTimeout(subscription::dispose);
        emitter.onCompletion(subscription::dispose);
        emitter.onError(subscription::dispose);

        return emitter;
    }*/

    /**
     * 前端使用示例：
     *
     * 1. 简单文本流（当前默认）：
     *    POST /interview/start
     *
     * 2. 带MP3音频的流：
     *    POST /interview/start-with-audio
     *    返回：{"type":"chunk","text":"问题内容","audio":"base64音频数据","format":"mp3"}
     *
     * 3. 前端播放音频示例代码：
     *    const audio = new Audio('data:audio/mp3;base64,' + audioData);
     *    audio.play();
     *
     * 4. 完整SSE事件处理：
     *    const eventSource = new EventSource('/interview/start-full-audio');
     *    eventSource.addEventListener('message', (event) => {
     *        const data = JSON.parse(event.data);
     *        if (data.type === 'chunk') {
     *            // 显示文本
     *            console.log(data.text);
     *            // 播放音频
     *            if (data.audio) {
     *                const audio = new Audio('data:audio/' + data.format + ';base64,' + data.audio);
     *                audio.play();
     *            }
     *        }
     *    });
     */

}
